#pragma once
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include "Socket.hpp"
#include "log.hpp"
#include <memory>

const int defaultsize=24;//设置poll的数量，这是静态写法，可以动态扩容
const int defaultfill=-1;//默认填充位
const int non_event=0;//没有事件

LOG lg(PRINT_TO_SCREEN);
//Poll相比于select的优势：
//1.poll的fd数组是一个结构体数组，每个结构体都有一个fd和events字段，而select的fd数组是一个int数组，只能监听可读事件
//2.poll的fd数组是动态扩容的，而select的fd数组是静态的，不存在1024的限制
//3.但是poll依然需要遍历fd数组，时间复杂度是O(n)，为了解决这个问题，可以使用epoll

class PollServer
{
public:
    PollServer(uint16_t port=8080)
            : port_(port)
    {
    }

    void Init()
    {
        listensocket_.Socket();
        listensocket_.Bind(port_);
        listensocket_.Listen();

        //初始化fd数组,全部设置为-1
        for(int i=0;i<defaultsize;++i)
        {
            fds[i].fd=defaultfill;
            fds[i].events=non_event;//由用户设置
            fds[i].revents=non_event;//由poll返回
        }
    }

    void PrintFd()
    {
        for(int i=0;i<defaultsize;++i)
        {
            if(fds[i].fd!=defaultfill)
            {
                std::cout<<fds[i].fd<<" ";
            }
        }
    }

    void HanderEvent()
    {
        for(int i=0;i<defaultsize;i++)
        {
            int fd=fds[i].fd;
            if(fd==defaultfill) continue;//跳过未使用的位
            else
            {
                if(fd==listensocket_.Getsocketfd())
                {
                    if(fds[i].revents&POLLIN)//用按位与的方式判断是否激活
                    {
                        int clientfd;
                        std::string client_ip;
                        uint16_t client_port;
                        if(listensocket_.Accept(clientfd,client_ip,client_port))
                        {
                            std::cout<<"Accept a new client: "<<client_ip<<":"<<client_port<<std::endl;
                            //将新的客户端socket放到数组中
                            int j=0;
                            for(;j<defaultsize;++j)
                            {
                                if(fds[j].fd==defaultfill)
                                {
                                    fds[j].fd=clientfd;
                                    fds[j].events=POLLIN;//新的客户端socket需要监听可读事件
                                    break;
                                }
                            }
                            //但其实这里可以扩容，这里只是简单的判断是否满了
                            if(j==defaultsize)
                            {
                                std::cerr<<"fd_array is full, cannot accept more client"<<std::endl;
                                close(clientfd);
                            }
                            PrintFd();
                        }
                    }
                }
                else//普通的客户端socket
                {
                    if(fds[i].revents&POLLIN)//用按位与
                    {
                        char buffer[1024];
                        ssize_t n=read(fd,buffer,sizeof(buffer)-1);
                        if(n>0)
                        {
                            buffer[n]='\0';
                            std::cout<<"Received from client fd "<<fd<<": "<<buffer<<std::endl;
                            //回显数据
                            //write(fd,buffer,n);
                        }
                        else if(n==0)
                        {
                            //客户端关闭了连接
                            std::cout<<"Client fd "<<fd<<" closed the connection"<<std::endl;
                            close(fd);
                            fds[i].fd=defaultfill;//将该位置重新设置为-1，表示未使用
                        }
                        else
                        {
                            std::cerr<<"read error on fd "<<fd<<", errno: "<<errno<<", errstring: "<<strerror(errno)<<std::endl;
                            close(fd);
                            fds[i].fd=defaultfill;//将该位置重新设置为-1，表示未使用
                        }
                    }
                }
            }
        }
    }

    void Start()
    {
        int fd=listensocket_.Getsocketfd();
        struct pollfd pfd;
        pfd.fd=fd;
        pfd.events=POLLIN;//监听socket只需要监听可读事件
        pfd.revents=non_event;//这里需要将revents设置为0，否则会影响后续的判断
        fds[0]=pfd;
        while(1)
        {
            sleep(1);
            int timeout=1000;//设置时间为1s
            int n=poll(fds,defaultsize,timeout);
            //select会对rfds进行修改，返回后只保留有事件的fd
            switch(n)
            {
                case 0:
                    std::cout<<"select timeout"<<std::endl;
                    break;
                case -1:
                    if(errno==EWOULDBLOCK)//这里是底层还未就绪
                    {
                        std::cout<<"select interrupted by signal"<<std::endl;
                        continue;
                    }
                    else
                    {
                        //否则是真的出错了
                        std::cerr<<"select error, errno: "<<errno<<", errstring: "<<strerror(errno)<<std::endl;
                    }
                    break;
                default:
                    HanderEvent();
                    break;
            }
        }

    }

    ~PollServer()
    {

    }
private:
    Sockets listensocket_;
    uint16_t port_;
//    struct pollfd *fds;//这里可以设置为指针，并且可以进行扩容
    struct pollfd fds[defaultsize];
};